package net.towee.client.gadgets.ads;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import net.towee.client.event.DocumentOpenEvent;
import net.towee.client.event.DocumentOpenEvent.DocumentOpenHandler;
import net.towee.client.event.DocumentOpenEvent.HasDocumentOpenHandlers;
import net.towee.client.event.MoreResultEvent;
import net.towee.client.event.MoreResultEvent.HasMoreResultHandlers;
import net.towee.client.event.MoreResultEvent.MoreResultHandler;
import net.towee.client.gadgets.GadgetView;
import net.towee.client.i18n.ToweeConstants;
import net.towee.client.resources.ClientResource;
import net.towee.client.widgets.DataHelpers;
import net.towee.client.widgets.ListItemWidget;
import net.towee.client.widgets.SpanPanel;
import net.towee.client.widgets.UnorderedListWidget;
import net.towee.model.repo.DocumentData;

import com.google.gwt.animation.client.Animation;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

public class AdsGadgetView extends GadgetView implements AdsGadget.Display, HasDocumentOpenHandlers,
		HasMoreResultHandlers, ResizeHandler {

	public class StepChangingAnimation extends Animation {
		private int currentStepLeft;
		private int moveStepLength;

		@Override
		protected void onUpdate(double progress) {
			steps.getElement().getStyle()
					.setProperty("left", ((currentStepLeft + (progress * moveStepLength)) * (-1)) + "px");
		}

		public void run(int duration, int widget) {
			currentStepLeft = steps.getElement().getOffsetLeft() * (-1);
			moveStepLength = items.get(widget).getElement().getOffsetLeft() - currentStepLeft;

			run(duration);
		}
	}

	private final LinkedList<Widget> items = new LinkedList<Widget>();
	private final Map<String, HasWidgets> documents = new HashMap<String, HasWidgets>();
	private final UnorderedListWidget steps;
	private final StepChangingAnimation animation;

	private final Label newButton = new Label();
	private final Label toRight = new Label();
	private final Label toLeft = new Label();
	
	private int newDocs = 0;
	private int lastNext = 0;
	private int showedDocs = 0;
	private int displayWidth = 0;
	private int currentStep = 0;
	private boolean noMore = false;

	@Inject
	public AdsGadgetView(ToweeConstants constants, ClientResource resource) {
		super(constants, resource);
		setHeight("300px");
		this.steps = new UnorderedListWidget();
		this.animation = new StepChangingAnimation();

		// For creating steps container with width of client
		Window.addResizeHandler(this);
		steps.getElement().setAttribute("items", "");
		steps.setWidth((displayWidth * 5) + "px");

		// Set lobby buttons
		addStyleName(resource.css().gadgetAds());

		// Set lobby steps
		add(steps);

		createNextButtons();
		createNewButton();
	}

	private void createNewButton() {
		newButton.setVisible(false);
		newButton.getElement().setAttribute("newButton", "");
		newButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				selectNextItem();
			}
		});
		add(newButton);
	}

	private void createNextButtons() {
		toRight.getElement().setAttribute("arrow", "right");
		toRight.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				selectNextItem();
			}
		});
		add(toRight);

		toLeft.getElement().setAttribute("arrow", "left");
		toLeft.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				selectPrevItem();
			}
		});
		add(toLeft);
		toLeft.setVisible(false);
	}

	public HasWidgets getContainerForNextStep(boolean newDoc) {
		ListItemWidget stepItem = new ListItemWidget();
		stepItem.getElement().setAttribute("item", "");
		stepItem.setWidth(displayWidth + "px");
		
		if(!newDoc) {
			steps.add(stepItem);
			items.add(stepItem);
		}
		else {
			steps.addFirst(stepItem);
			items.addFirst(stepItem);
		}

		FlowPanel container = new FlowPanel();
		container.getElement().setAttribute("container", "");
		stepItem.add(container);

		updateSize();
		return container;
	}

	private void selectPrevItem() {
		if(currentStep > 0) {
			currentStep--;
			animation.run(360, currentStep);
			toRight.setVisible(true);
			
			if(currentStep == 0)
				toLeft.setVisible(false);
		}
	}

	public void selectNextItem() {
		// Get mode result if we in
		if (currentStep >= showedDocs - 2 && !noMore)
			MoreResultEvent.fire(this);

		if (currentStep < showedDocs-1) {
			currentStep++;
			animation.run(360, currentStep);
			toLeft.setVisible(true);

			if (currentStep > lastNext) {
				lastNext++;

				if (newDocs > 0) {
					newDocs--;

					if (newDocs > 0)
						this.newButton.setText("еще " + newDocs);
					else
						this.newButton.setVisible(false);
				}
			}
			
			if(currentStep == showedDocs-1 && noMore)
				toRight.setVisible(false);
		}
	}

	private void updateSize() {
		if (getOffsetWidth() > 0) {
			displayWidth = getOffsetWidth() - 10;
			steps.setWidth((displayWidth * steps.getWidgetCount()) + "px");

			if (steps.getWidgetCount() > 0) {
				for (Widget w : items)
					w.setWidth(displayWidth + "px");

				steps.getElement()
						.getStyle()
						.setProperty("left",
								items.get(currentStep).getElement().getOffsetLeft() * (-1) + "px");
			}
		}
	}

	@Override
	public void onAttach() {
		super.onAttach();
		updateSize();
	}

	@Override
	public void onResize(ResizeEvent event) {
		updateSize();
	}

	@Override
	public void clearDocuments() {
		steps.clear();
	}

	@Override
	public void showDocument(final DocumentData doc, boolean newDoc) {
		HasWidgets container = getContainerForNextStep(newDoc);

		// Create header
		FlowPanel header = new FlowPanel();
		header.getElement().setAttribute("document", "header");

		// Create name
		FlowPanel nameContainer = new FlowPanel();
		Anchor name = new Anchor(doc.getIdentity().getName());
		nameContainer.getElement().setAttribute("name", "");
		nameContainer.add(name);
		nameContainer.add(new SpanPanel("-"));
		nameContainer.add(new SpanPanel(doc.getIdentity().getGroup().getPrintName()));
		header.add(nameContainer);

		name.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				DocumentOpenEvent.fire(AdsGadgetView.this, doc);
			}
		});

		// Create author and date
		SpanPanel auth = new SpanPanel(doc.getIdentity().getAuthor().getFullName());
		Widget date = DataHelpers.formattedDateTimeWidget(doc.getUpdateDate());
		auth.getElement().setAttribute("author", "");
		date.getElement().setAttribute("date", "");

		FlowPanel info = new FlowPanel();
		info.getElement().setAttribute("info", "");
		info.add(new SpanPanel(constants.author()));
		info.add(auth);
		info.add(new SpanPanel(constants.by()));
		info.add(date);
		header.add(info);
		container.add(header);

		// Create text container
		HTML text = new HTML(doc.getDescription());
		text.getElement().setAttribute("text", "");
		container.add(text);
		
		// Remove old
		if(documents.containsKey( doc.getIdentity().getId() )) {
			Widget w = (Widget)documents.get( doc.getIdentity().getId() );
			items.remove(w);
			w.removeFromParent();
		}
		
		documents.put( doc.getIdentity().getId(), container );

		if(showedDocs++ == 0)
			toLeft.setVisible(false);
		
		if(!newDoc)
			toRight.setVisible(true);
		else {
			currentStep = 0;
			lastNext++;
			animation.run(360, 0);
		}
	}

	@Override
	public void setNewDocumentsCount(Integer result) {
		if (result > 1) {
			newDocs = result - 1;
			newButton.setVisible(true);
			newButton.setText("еще " + newDocs);
		}
	}

	@Override
	public void onLoadingStart() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onLoadingEnd() {
		// TODO Auto-generated method stub

	}

	@Override
	public void noMore() {
		noMore = true;
	}

	@Override
	public HandlerRegistration addMoreResultHandler(MoreResultHandler handler) {
		return addHandler(handler, MoreResultEvent.getType());
	}

	@Override
	public HandlerRegistration addDocumentOpenHandler(DocumentOpenHandler handler) {
		return addHandler(handler, DocumentOpenEvent.getType());
	}

	@Override
	public HasMoreResultHandlers getMoreResultHandlers() {
		return this;
	}

	@Override
	public HasDocumentOpenHandlers getDocumentOpener() {
		return this;
	}

}